// 初始化PTP头
#include <stdio.h>
#include <cstdint>
#include <string.h>
#include <netinet/in.h>
#include "ptp.h"

uint8_t temp[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 时钟标识
// extern Port_delay port_delay;
// 初始化PTP头
int init(PtpHeader *ptpheader, PtpMsgType type, uint16_t sequence_id)
{
    uint8_t src_mac[6] = {0xc8, 0x09, 0xa8, 0xe6, 0x9a, 0xc9}; // 设置源网卡地址
    uint8_t dst_mac[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}; // 设置目的网卡地址

    memcpy(ptpheader->dmac, dst_mac, sizeof(dst_mac));
    memcpy(ptpheader->smac, src_mac, sizeof(src_mac));
    ptpheader->eth_type = htons(0x88F7);
    // 测试数据，实际需要修改
    ptpheader->major_sdo_id = 0x1; // sdoID的高4位有效位，gPTP将该值设为0x1
    ptpheader->message_type = static_cast<uint8_t>(type);
    ptpheader->version_ptp = 0x2;       // 该字段是当前同步域内支持IEEE1588的版本，802.1AS将该字段设置为0x2.
    ptpheader->minor_version_ptp = 0x1; // PTP主版本：该字段是当前同步域内支持IEEE1588的版本，802.1AS将该字段设置为0x1.

    // ptpheader->domain_number = 0x01; // 同步域编号：消息类型为Pdelay_Req, Pdelay_Resp，Pdelay_Resp_Follow_Up 的消息该字段为0，其他类型的报文设置为非0值。
    ptpheader->minor_sdo_id = 0x00; // 同步域标识sdoID的低8位有效位，gPTP默认为0x00

    // ptpheader->correction_field = 0x123456789ABCDEF0; // 延时修正域：当报文被记录时间戳时，会存在部分动态或者静态延时导致时间戳不准确，这部分干扰延时累加记录在该字段。
    ptpheader->correction_field = 0x0000000000000000;
    // ptpheader->message_type_specific = 0x12345678; // 根据Sync Delay_Req Delay_Resp消息类型的不同，这个字段的值会有不同的语义，具体和内部实现有关。如果不需要则默认为0.
    ptpheader->message_type_specific = 0x00000000;
    // ptpheader->message_length = 60;
    // ptpheader->flags = 0;
    memcpy(ptpheader->clock_identify, temp, sizeof(temp)); // 一个8字节的变量，用于唯一标识PTP网络内的独立实体，可有用户定义（一般为mac地址创建）
    ptpheader->port_number = 0x1;                          // 端口号：设置范围1~0xFFFE，由用户为每个逻辑端口自定义。
    ptpheader->sequence_id = htons(sequence_id);           // 序列号，之后需要更改
    // ptpheader->control_field = 0x05;
    switch (type)
    {
    case E_SIGNAL:
        ptpheader->message_length = htons(PTP_SIGNAL_LENGTH);
        ptpheader->flags = htons(0x0208);
        ptpheader->log_message_interval = 127;
        break;
    case E_SYNC:
        ptpheader->message_length = htons(PTP_SYNC_LENGTH);
        // ptpheader->flags |= PTP_TIMESCALE;
        // ptpheader->flags |= TOW_STEP;
        ptpheader->flags = htons(0x0208);
        ptpheader->control_field = 0;
        ptpheader->log_message_interval = 0;
        ptpheader->domain_number = 0x00;
        break;
    case E_PDELAY_REQ:
        ptpheader->message_length = PTP_PDELAY_REQ_LENGTH;
        // ptpheader->major_sdo_id = 2;
        ptpheader->control_field = 0x05;
        ptpheader->flags = htons(0x0208);
        ptpheader->log_message_interval = 127;
        ptpheader->domain_number = 0x00;
        break;
    case E_PDELAY_RESP:
        ptpheader->message_length = htons(PTP_PDELAY_RESP_LENGTH);
        // ptpheader->major_sdo_id = 2;
        ptpheader->control_field = 0x05;
        // ptpheader->flags |= PTP_TIMESCALE;
        // ptpheader->flags |= TOW_STEP;
        ptpheader->flags = htons(0x0208);
        ptpheader->log_message_interval = 127;
        ptpheader->domain_number = 0x00;
        break;
    case E_PDELAY_RESP_FOLLOW_UP:
        ptpheader->message_length = htons(PTP_PDELAY_RESP_FLLOW_UP_LENGTH);
        // ptpheader->major_sdo_id = 2;
        ptpheader->control_field = 0x05;
        // ptpheader->flags |= PTP_TIMESCALE;
        ptpheader->flags = htons(0x0208);
        ptpheader->log_message_interval = 127;
        ptpheader->domain_number = 0x00;
        break;
    case E_FOLLOW_UP:
        ptpheader->message_length = htons(PTP_FOLLOW_UP_LENGTH);
        // ptpheader->flags |= PTP_TIMESCALE;
        ptpheader->flags = htons(0x0208);
        ptpheader->control_field = 0x02;
        ptpheader->log_message_interval = 127;
        ptpheader->domain_number = 0x00;
        break;
    case E_ANNOUNCE:
        ptpheader->message_length = PTP_FOLLOW_UP_LENGTH;
        ptpheader->control_field = 0x05;
        ptpheader->flags = htons(0x0208);
        ptpheader->log_message_interval = 127;
        break;
    default:
        return -1;
    }

    return 0;
}

// 十字节转八字节
uint64_t t2e(uint8_t *buffer)
{
    uint32_t second = 0;
    uint32_t nanosecond = 0;

    memcpy(&second, buffer + 2, 4);
    memcpy(&nanosecond, buffer + 6, 4);

    second = ntohl(second);
    nanosecond = ntohl(nanosecond);

    uint64_t t = ((uint64_t)second << 32) | nanosecond;
    return t;
}

// 八字节转十字节
uint8_t *e2t(uint64_t t, uint8_t t3[10])
{
    for (int i = 0; i < 8; i++)
    {
        t3[i + 2] = (t >> (8 * (7 - i))) & 0xff;
    }
    t3[0] = 0;
    t3[1] = 0;
    // for (int i = 0; i < 8; i++)
    // {
    //     printf("t3:%x\n", t3[i]);
    // }
    return t3;
}

uint32_t extract_seconds(uint64_t timestamp)
{
    return (uint32_t)(timestamp >> 32); // 右移32位得到秒部分
}

uint32_t extract_nanoseconds(uint64_t timestamp)
{
    return (uint32_t)(timestamp & 0xFFFFFFFF); // 与操作保留低32位得到纳秒部分
}